package blingking.jfinal.orm.autoconfigure;

import blingking.jfinal.orm.aop.JFinalORMTxAop;
import blingking.jfinal.orm.bean.JFMappingBean;
import blingking.jfinal.orm.datasource.JFinalORMDataSource;
import blingking.jfinal.orm.properties.JFinalORMProperties;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import io.shardingsphere.shardingjdbc.jdbc.core.datasource.ShardingDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.*;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Import;

import javax.annotation.PostConstruct;
import javax.sql.DataSource;
import java.util.*;

/**
 * @author King
 * @description
 * @Date 2020/3/22
 */
@Configuration
@Import({JFinalORMTxAop.class})
@AutoConfigureAfter({JFinalORMDataSourceAutoConfiguration.class, DataSourceAutoConfiguration.class})
@EnableConfigurationProperties(JFinalORMProperties.class)
public abstract class JFinalORMAutoConfiguration {


    @Configuration("sbDSConfig")
    public class SpringBootDataSourceAutoConfig extends AbstractDataSourceAutoConfiguration {

        @Autowired
        DataSource dataSource;

        @Override
        @PostConstruct
        public void init() {
            super.config();
        }

        @Override
        protected Map<String, DataSource> getDataSources() {
            Map<String, DataSource> dataSourceMap = applicationContext.getBeansOfType(DataSource.class);
            dataSourceMap.values().removeIf(value->(value instanceof JFinalORMDataSource || "io.shardingsphere.shardingjdbc.jdbc.core.datasource.ShardingDataSource".equals(value.getClass().getName())));
            return initDataSources(dataSourceMap);
        }

    }

    @Configuration("jfDSConfig")
    public class JFinalORMDataSourceAutoConfig  extends AbstractDataSourceAutoConfiguration {
        @Autowired
        DataSource dataSource;

        @Override
        @PostConstruct
        public void init() {
            super.config();
        }

        @Override
        protected Map<String, DataSource> getDataSources() {
            if (dataSource instanceof JFinalORMDataSource){
                return (JFinalORMDataSource)dataSource;
            }else {
                return null;
            }
        }
    }

    @Configuration
    @DependsOn({"jfDSConfig","sbDSConfig"})
    @ConditionalOnClass(name = "io.shardingsphere.shardingjdbc.spring.boot.SpringBootConfiguration")
    @ConditionalOnBean(DataSource.class)
    public class ShardingJdbcDataSourceAutoConfig  extends AbstractDataSourceAutoConfiguration {
        @Autowired
        ShardingDataSource dataSource;

        @Override
        @PostConstruct
        public void init() {
            this.config();
        }


        @Override
        protected void config() {
            Map<String, DataSource> dataSourceMap = getDataSources();
            if (dataSourceMap!=null&&dataSourceMap.size()>0){
                dataSourceMap.forEach((k, v) -> addARP(k, v, dataSource));
                addShardingModel();
                startARP();
            }
        }

        @Override
        protected Map<String, DataSource> getDataSources() {
            Map<String, DataSource> dataSourceMap = dataSource.getDataSourceMap();
            return initDataSources(dataSourceMap);

        }

        private void addShardingModel() {
            for (JFMappingBean jfMappingBean : allJFMappingBeans) {
                if (!isExist(jfMappingBean.getClazz())) {
                    String tableName = jfMappingBean.getTableName();
                    if (allARPs.size() > 0) {
                        for (ActiveRecordPlugin activeRecordPlugin : allARPs){
                            if (activeRecordPlugin.getConfig().getDataSource() instanceof ShardingDataSource){
                                activeRecordPlugin.addMapping(tableName, jfMappingBean.getClazz());
                                addedMappingClasses.add(jfMappingBean.getClazz());
                                break;
                            }
                        }

                    }
                }
            }
        }
    }







}

